package com.sky.d_pooling;

import java.io.IOException;
import java.io.InterruptedIOException;
import java.net.UnknownHostException;
import java.security.NoSuchAlgorithmException;

import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLException;

import org.apache.http.HttpEntityEnclosingRequest;
import org.apache.http.HttpRequest;
import org.apache.http.client.HttpRequestRetryHandler;
import org.apache.http.client.config.CookieSpecs;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.protocol.HttpClientContext;
import org.apache.http.config.Registry;
import org.apache.http.config.RegistryBuilder;
import org.apache.http.conn.ConnectTimeoutException;
import org.apache.http.conn.socket.ConnectionSocketFactory;
import org.apache.http.conn.socket.LayeredConnectionSocketFactory;
import org.apache.http.conn.socket.PlainConnectionSocketFactory;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
import org.apache.http.protocol.HttpContext;

/**
 * HttpClient4.5.2 连接池
 * http://www.cnblogs.com/likaitai/p/5431246.html
 * @Author:hjt
 */
public class HttpConnectionManager {

	/**
	 为什么使用HTTP连接池
	  	降低延迟：不采用连接池，每次请求都会重新建立连接（握手3次），用完关闭连接（4次挥手）
	  		采用连接池减少这部分时间损耗
	  	支持更大并发：每次连接打开一个端口，大并发下系统端口会很快被用完
	 */
	
	 /** 
     * 最大连接数 
     */  
    public final static int MAX_TOTAL_CONNECTIONS = 800;  
    /** 
     * 获取连接的最大等待时间 
     */  
    public final static int WAIT_TIMEOUT = 60000;  
    /** 
     * 每个路由最大连接数 
     */  
    public final static int MAX_ROUTE_CONNECTIONS = 400;  
    /** 
     * 连接超时时间 
     */  
    public final static int CONNECT_TIMEOUT = 10000;  
    /** 
     * 读取超时时间 
     */  
    public final static int READ_TIMEOUT = 10000;  
    
	
	private static PoolingHttpClientConnectionManager phccm = null;
	
	static {
		try {
			LayeredConnectionSocketFactory layeredFactory = new SSLConnectionSocketFactory(SSLContext.getDefault());
			
			Registry<ConnectionSocketFactory> socketFactoryRegistry = RegistryBuilder.<ConnectionSocketFactory>create()
					.register("https", layeredFactory)
					.register("http", new PlainConnectionSocketFactory())
					.build();
			phccm = new PoolingHttpClientConnectionManager(socketFactoryRegistry);
			phccm.setMaxTotal(MAX_TOTAL_CONNECTIONS);
			phccm.setDefaultMaxPerRoute(MAX_ROUTE_CONNECTIONS);
			
		} catch (NoSuchAlgorithmException e) {
			e.printStackTrace();
		}
		
	}
	
	 //请求重试机制  
    private static HttpRequestRetryHandler retryHandler = new HttpRequestRetryHandler() {  
        public boolean retryRequest(IOException exception, int executionCount, HttpContext context) {  
            if (executionCount >= 3) {  
                // 超过三次则不再重试请求  
                return false;  
            }  
            if (exception instanceof InterruptedIOException) {  
                // Timeout  
                return false;  
            }  
            if (exception instanceof UnknownHostException) {  
                // Unknown host  
                return false;  
            }  
            if (exception instanceof ConnectTimeoutException) {  
                // Connection refused  
                return false;             
            }  
            if (exception instanceof SSLException) {  
                // SSL handshake exception  
                return false;  
            }  
            HttpClientContext clientContext = HttpClientContext.adapt(context);  
            HttpRequest request = clientContext.getRequest();  
            boolean idempotent = !(request instanceof HttpEntityEnclosingRequest);  
            if (idempotent) {  
                // Retry if the request is considered idempotent  
                return true;  
            }  
            return false;  
        }  
    };  
	
	public static CloseableHttpClient getHttpClient(){
		RequestConfig requestConfig =  RequestConfig.custom()
				.setConnectTimeout(CONNECT_TIMEOUT)
				.setSocketTimeout(CONNECT_TIMEOUT)
				.setCookieSpec(CookieSpecs.DEFAULT)
				.build();
		
		
		CloseableHttpClient httpClient = HttpClients.custom()
				.setConnectionManager(phccm)
				.setDefaultRequestConfig(requestConfig)
				.setRetryHandler(retryHandler)
				.build();
		
		//不使用连接池创建方法
//		CloseableHttpClient httpClient = HttpClients.createDefault();
		return httpClient;
	}
	
}
